home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xhearts / hearts_dist.c < prev    next >
C/C++ Source or Header  |  1995-05-09  |  11KB  |  442 lines

  1. /*
  2.  * hearts_dist - distributor for hearts
  3.  *
  4.  * Keeps track of games in progress and allows new players to select which
  5.  * game to join or start a new game.
  6.  *
  7.  *
  8.  *    Commands to hearts player:
  9.  *  tn        Following info regards table n (n is unique identifier).
  10.  *  hn        Now playing hand n.
  11.  *  rn        Now playing round n.
  12.  *  pn<name>    Player n is <name>.
  13.  *
  14.  *  xn        Table n has exited (game over).
  15.  *  g        Get table number to join.
  16.  *  cn        Connect to dealer on port n.
  17.  *
  18.  *    Commands from hearts player:
  19.  *  jn        Join table n.
  20.  *  n        Start new game.
  21.  *
  22.  *    Commands to dealer:
  23.  * none yet?!?
  24.  *
  25.  *    Commands from dealer:
  26.  *  hn        Now playing hand n.
  27.  *  rn        Now playing round n.
  28.  *  pn<name>    Player n is <name>.
  29.  *
  30.  */
  31. /*
  32.  * MODIFICATION HISTORY
  33.  *
  34.  * S001    rr@sco.com    14 May 93
  35.  *    - Use Internet Domain sockets rather than Unix Domain sockets
  36.  * S002    mikep@sco.com    22 June 93
  37.  *    - Fix bug in socket call.  Need to save the fd in socks[x]
  38.  *    Note this don't work yet.
  39.  */
  40.  
  41. #include "misc.h"
  42. #include "defs.h"
  43. #include "local.h"
  44. #include <string.h>
  45. #include <malloc.h>
  46.  
  47. typedef struct table *table_ptr;
  48.  
  49. struct table {
  50.     table_ptr    next_table;        /* Points to next table entry */
  51.     int        table_id;        /* Unique identifier */
  52.     char        player_name[4][9];    /* Name of players at table */
  53.     int        hand;            /* Current dealer hand (1..4) */
  54.     int        round;            /* Current round (1..13) */
  55.     int        port_num;        /* Port # assigned */
  56.     int        socket;            /* File descriptor for dealer */
  57.     int        pid;            /* Process id for dealer */
  58. };
  59.  
  60. typedef struct empty_table *empty_ptr;
  61.  
  62. struct empty_table {
  63.     empty_ptr    next_empty;
  64.     int        port_num;        /* Available port # */
  65. };
  66.  
  67. typedef struct new_comer *new_ptr;
  68.  
  69. struct new_comer {
  70.     new_ptr        next_new_comer;
  71.     int        socket;            /* File descriptor */
  72. };
  73.  
  74. table_ptr    first_table;
  75. empty_ptr    first_empty;
  76. new_ptr        first_new_comer;
  77.  
  78. int    main_sock,
  79.     next_port,                /* Next port to assign */
  80.     unique_id;
  81.  
  82. /*
  83.  * clear_table - dealer went away; drop that table.
  84.  */
  85. clear_table(tbl_ptr)
  86. table_ptr    tbl_ptr;
  87. {
  88.     table_ptr    prev_ptr = NULL;
  89.     table_ptr    cur_ptr;
  90.     empty_ptr    temp_empty, cur_empty;
  91.     new_ptr        cur_new_comer;
  92.     char        buf[16];
  93.  
  94.     while (wait(0) != tbl_ptr->pid)        /* Wait for process to die */
  95.         ;
  96.     (void) close(tbl_ptr->socket);
  97.     /*
  98.      * Inform new-comers
  99.      */
  100.     (void) sprintf(buf, "x%d", tbl_ptr->table_id);
  101.     for (cur_new_comer = first_new_comer; cur_new_comer;
  102.             cur_new_comer = cur_new_comer->next_new_comer)
  103.         write_socket(cur_new_comer->socket, buf);
  104.     for (cur_ptr = first_table; cur_ptr != tbl_ptr;
  105.                     cur_ptr = cur_ptr->next_table)
  106.         prev_ptr = cur_ptr;
  107.     if (prev_ptr)
  108.         prev_ptr->next_table = tbl_ptr->next_table;
  109.     else
  110.         if ((first_table = tbl_ptr->next_table) == NULL &&
  111.             first_new_comer == NULL)
  112.             exit(0);    /* No more dealers */
  113.             ;
  114.      if (first_table) {
  115.     temp_empty = (empty_ptr) malloc(sizeof(struct empty_table));
  116.     temp_empty->next_empty = NULL;
  117.     temp_empty->port_num = tbl_ptr->port_num;
  118.     free((char *) tbl_ptr);
  119.     if (first_empty) {
  120.         for (cur_empty = first_empty; cur_empty->next_empty;
  121.                     cur_empty = cur_empty->next_empty) ;
  122.         cur_empty->next_empty = temp_empty;
  123.     }
  124.     else
  125.         first_empty = temp_empty;
  126.       }
  127. }
  128.  
  129. /*
  130.  * drop_new_comer - New comer exited
  131.  */
  132. drop_new_comer(dead_new_comer)
  133. new_ptr    dead_new_comer;
  134. {
  135.     new_ptr    cur_new_comer,
  136.         prev_new_comer = NULL;
  137.  
  138.     (void) close(dead_new_comer->socket);
  139.     for (cur_new_comer = first_new_comer; cur_new_comer != dead_new_comer;
  140.             cur_new_comer = cur_new_comer->next_new_comer)
  141.         prev_new_comer = cur_new_comer;
  142.     if (prev_new_comer)
  143.         prev_new_comer->next_new_comer = dead_new_comer->next_new_comer;
  144.     else
  145.         first_new_comer = dead_new_comer->next_new_comer;
  146.     free((char *) dead_new_comer);
  147.     if ((first_table == NULL) && (first_new_comer == NULL))
  148.         exit(0);        /* Nobody connected */
  149. }
  150.  
  151. /*
  152.  * new_player - New player has connected.  Inform of games in progress and
  153.  *        request game to be joined.
  154.  */
  155. new_player()
  156. {
  157.     int    new_socket;        /* new file descriptor */
  158.     char    buf[64];
  159.     struct    sockaddr_in sockad;
  160.     int    ssize;            /* makes accept happy */
  161.     int    i;
  162.     new_ptr        cur_new_comer, temp_new_comer;
  163.     table_ptr    cur_ptr;
  164.  
  165.     /*
  166.      * add whoever's waiting
  167.      */
  168.     ssize = sizeof (sockad);
  169.     if ((new_socket = accept(main_sock, &sockad, &ssize)) == -1) {
  170.         perror("accept");
  171.         exit(-1);
  172.     }
  173.     /*
  174.      * add to list of new_comers
  175.      */
  176.     temp_new_comer = (new_ptr) malloc(sizeof(struct new_comer));
  177.     temp_new_comer->next_new_comer = NULL;
  178.     temp_new_comer->socket = new_socket;
  179.     if (first_new_comer) {
  180.         for (cur_new_comer = first_new_comer;
  181.             cur_new_comer->next_new_comer;
  182.             cur_new_comer = cur_new_comer->next_new_comer) ;
  183.         cur_new_comer->next_new_comer = temp_new_comer;
  184.     }
  185.     else {
  186.         first_new_comer = temp_new_comer;
  187.         first_new_comer->next_new_comer = NULL;
  188.     }
  189.     /*
  190.      * send info on games in progress
  191.      */
  192.     for (cur_ptr = first_table; cur_ptr; cur_ptr = cur_ptr->next_table) {
  193.         (void) sprintf(buf, "t%d", cur_ptr->table_id);
  194.         write_socket(new_socket, buf);
  195.         (void) sprintf(buf, "h%d", cur_ptr->hand);
  196.         write_socket(new_socket, buf);
  197.         (void) sprintf(buf, "r%d", cur_ptr->round);
  198.         write_socket(new_socket, buf);
  199.         for (i = 0; i < 4; i++) {
  200.             (void) sprintf(buf, "p%d%s", i, cur_ptr->player_name[i]);
  201.             write_socket(new_socket, buf);
  202.         }
  203.     }
  204.     write_socket(new_socket, "g");
  205. }
  206.  
  207. tell_new_comers(buf)
  208. char    *buf;
  209. {
  210.     new_ptr    cur_new;
  211.  
  212.     for (cur_new = first_new_comer; cur_new;
  213.             cur_new = cur_new->next_new_comer)
  214.         write_socket(cur_new->socket, buf);
  215. }
  216.  
  217. /*
  218.  * join - join an existing table.  table_num is unique identifier for table.
  219.  */
  220. join(table_num, socket)
  221. int    table_num, socket;
  222. {
  223.     table_ptr    cur_ptr;
  224.     char    buf[16];
  225.  
  226.     for (cur_ptr = first_table; cur_ptr && cur_ptr->table_id != table_num;
  227.                     cur_ptr = cur_ptr->next_table) ;
  228.     if (cur_ptr) {
  229.         (void) sprintf(buf, "c%d", cur_ptr->port_num);
  230.         write_socket(socket, buf);
  231.     }
  232.     else
  233.         write_socket(socket, "g");    /* Table doesn't exist?!? */
  234. }
  235.  
  236. /*
  237.  * new_table - start new hearts game.
  238.  */
  239. new_table(cur_new_comer)
  240. new_ptr    cur_new_comer;
  241. {
  242.     table_ptr    cur_table, new_tbl_ptr;
  243.     empty_ptr    tmp_empty;
  244.     int        i, socks[2];
  245.     int        dealer_port, dealer_socket, retry = 0;
  246.     char    buf[16], filename[1024];
  247.  
  248.     new_tbl_ptr = (table_ptr) malloc(sizeof(struct table));
  249.     new_tbl_ptr->next_table = NULL;
  250.     new_tbl_ptr->table_id = ++unique_id;
  251.     for (i = 0; i < 4; i++)
  252.         (void) strcpy(new_tbl_ptr->player_name[i], "<empty>");
  253.     /*
  254.      * Assign a port.  Reassign a used port if available.
  255.      */
  256.     do {
  257.         if (first_empty) {
  258.             dealer_port = first_empty->port_num;
  259.             tmp_empty = first_empty;
  260.             first_empty = first_empty->next_empty;
  261.             free((char *) tmp_empty);
  262.         }
  263.         else
  264.             dealer_port = next_port++;
  265.         /*
  266.          * Make sure port is ok before assigning.
  267.          */
  268.         if ((dealer_socket = open_socket(dealer_port)) == 0)
  269.             if (++ retry == 20) {
  270.                 fputs("Can't open a dealer port!\n", stderr);
  271.                 exit(1);
  272.             }
  273.     }
  274.     while (dealer_socket == 0);
  275.     new_tbl_ptr->port_num = dealer_port;
  276.     /*
  277.      * Open a socket pair to talk to dealer on.
  278.      */
  279.     if (socks[0] = socket(AF_INET, SOCK_STREAM, 0) == -1) {    /* S002 */
  280.         perror("socket[0]");
  281.         exit(1);
  282.     }
  283.     if (socks[1] = socket(AF_INET, SOCK_STREAM, 0) == -1) {    /* S002 */
  284.         perror("socket[1]");
  285.         exit(1);
  286.     }
  287.     switch (new_tbl_ptr->pid = fork()) {
  288.     case 0:
  289.         (void) setpgrp (0, getpid());
  290.         (void) close(socks[0]);
  291.         if (socks[1] != 3)
  292.             (void) dup2(socks[1], 3);    /* Remap to fd 3 */
  293.         if (dealer_socket != 4)
  294.             (void) dup2(dealer_socket, 4);    /* Remap to fd 4 */
  295.         sprintf(filename, "%s/%s", HEARTSLIB, HEARTSD);
  296.         execl (filename, "heartsd", 0);
  297.         exit(1);
  298.     case -1:
  299.         perror("fork");
  300.         exit(1);
  301.     }
  302.     (void) close(socks[1]);
  303.     (void) close(dealer_socket);
  304.  
  305.     new_tbl_ptr->socket = socks[0];
  306.     if (first_table) {
  307.         for (cur_table = first_table; cur_table->next_table;
  308.             cur_table = cur_table->next_table)
  309.             ;
  310.         cur_table->next_table = new_tbl_ptr;
  311.     }
  312.     else
  313.         first_table = new_tbl_ptr;
  314.     /*
  315.      * Inform hearts player of port # to connect on.
  316.      */
  317.     (void) sprintf(buf, "c%d", dealer_port);
  318.     write_socket(cur_new_comer->socket, buf);
  319. }
  320.  
  321. main(argc, argv)
  322. char **argv;
  323. {
  324.     fd_type        read_fd;
  325.     table_ptr    cur_table;
  326.     new_ptr        cur_new_comer;
  327.     char        buf[64], tmp_buf[64];
  328.     int        ret;
  329.     int        table_num;
  330.     char        debug = FALSE;
  331.  
  332.     while (*++argv) {
  333.         if (**argv == '-') {
  334.             while (*++*argv) {
  335.                 switch (**argv) {
  336.                 case 'd':
  337.                     debug = TRUE;
  338.                     break;
  339.  
  340.                 default:
  341.                     fprintf (stderr, "usage: hearts_dist [-d]\n");
  342.                     exit (1);
  343.                     break;
  344.                 }
  345.             }
  346.         }
  347.     }
  348.  
  349.     first_table = NULL;
  350.     first_empty = NULL;
  351.     first_new_comer = NULL;
  352.     next_port = DIST_PORT;
  353.     unique_id = 0;
  354.  
  355.     if ((main_sock = open_socket(PORT)) == 0) {
  356.         fputs("Distributor port in use!\n", stderr);
  357.         exit(1);
  358.     }
  359.     if (!debug) {
  360.         /*
  361.          * Fork off and die.  Thus hearts invoker wait() returns.
  362.          * This signals ready to connect.
  363.          */
  364.         if (fork())
  365.             exit (0);
  366.     }
  367.  
  368.     for (;;) {
  369.         fd_init(main_sock, &read_fd);
  370.         /*
  371.          * Build mask for dealers
  372.          */
  373.         for (cur_table = first_table; cur_table;
  374.                 cur_table = cur_table->next_table)
  375.             fd_set(cur_table->socket, &read_fd);
  376.         /*
  377.          * Build mask for new_comers
  378.          */
  379.         for (cur_new_comer = first_new_comer; cur_new_comer;
  380.                 cur_new_comer = cur_new_comer->next_new_comer)
  381.             fd_set(cur_new_comer->socket, &read_fd);
  382.  
  383.         /*
  384.          * Wait for something to happen
  385.          */
  386.         if (select(WIDTH, &read_fd, (fd_type *) 0, (fd_type *) 0,
  387.                 (struct timeval *) 0)) {
  388.             if (fd_isset(main_sock, read_fd))
  389.                 new_player();
  390.             for (cur_table = first_table; cur_table;
  391.                     cur_table = cur_table->next_table)
  392.                 if (fd_isset(cur_table->socket, read_fd)) {
  393.                     /*
  394.                      * Message from dealer
  395.                      */
  396.                     ret = read_socket(cur_table->socket, buf);
  397.                     if (!ret) {
  398.                         clear_table(cur_table);
  399.                         break;
  400.                     } else {
  401.                         switch (buf[0]) {
  402.                         case 'h' :
  403.                             (void) sscanf(buf + 1, "%d", &cur_table->hand);
  404.                             break;
  405.                         case 'r' :
  406.                             (void) sscanf(buf + 1, "%d", &cur_table->round);
  407.                             break;
  408.                         case 'p' :
  409.                             (void) strcpy(cur_table->player_name[buf[1] - '0'], buf + 2);
  410.                         }
  411.                         (void) sprintf(tmp_buf, "t%d", cur_table->table_id);
  412.                         tell_new_comers(tmp_buf);
  413.                         tell_new_comers(buf);
  414.                     }
  415.                 }
  416.             for (cur_new_comer = first_new_comer; cur_new_comer;
  417.                 cur_new_comer = cur_new_comer->next_new_comer)
  418.                 if (fd_isset(cur_new_comer->socket, read_fd)) {
  419.                     /*
  420.                      * Message from newcomer
  421.                      */
  422.                     ret = read_socket(cur_new_comer->socket, buf);
  423.                     if (ret)
  424.                         switch (buf[0]) {
  425.                         case 'j' :
  426.                             (void) sscanf(buf + 1, "%d", &table_num);
  427.                             join(table_num, cur_new_comer->socket);
  428.                             break;
  429.  
  430.                         case 'n' :
  431.                             new_table(cur_new_comer);
  432.                         }
  433.                     else {
  434.                         drop_new_comer(cur_new_comer);
  435.                         break;
  436.                          }
  437.                 }
  438.         }
  439.     }
  440. }
  441.  
  442.